package com.doudou.zuul.filter;

import com.doudou.zuul.config.AppConfig;
import com.doudou.zuul.entity.ZuulResponseConstant;
import com.doudou.zuul.utils.TokenUtils;
import com.doudou.zuul.utils.ZuulFilterResponseUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zssj.redis.utils.RedisStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 检查access_token 是不是在黑名单
 */
@Component
public class AccessTokenBlacklistFilter extends ZuulFilter implements InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(AccessTokenBlacklistFilter.class);

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private RedisStringUtils redisStringUtils;

    @Override
    public String filterType() {
        return FilterConstants.ROUTE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 3;
    }

    @Override
    public boolean shouldFilter() {

        RequestContext ctx = RequestContext.getCurrentContext();

        if (!ctx.sendZuulResponse()) {
            return false;
        }
        //过滤所有请求
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String accessToken = null;

        //提取token，并且校验格式
        try {
            accessToken = TokenUtils.extractAccessToken(request);
        } catch (RuntimeException e) {

            LOGGER.info("zuul gate-way token parse exception: {}",
                    e.getMessage(),
                    e);

            String message = ZuulFilterResponseUtils.viewTipsMessage(
                    appConfig.isEnableLocalLogPrefix(),
                    appConfig.getLocalAppName(),
                    ZuulResponseConstant.ILLEGAL_TOKEN
            );

            ZuulFilterResponseUtils.sendResponse(ctx,
                    600,
                    message,
                    e.getMessage());
            return null;
        }

        //没有token直接放行
        if (StringUtils.isEmpty(accessToken)) {
            return null;
        }

        //检查黑名单
        Boolean inBlackList;
        try {
            inBlackList = accessTokenInBlacklist(accessToken);
        } catch (Exception e) {

            LOGGER.info("zuul gate-way token parse exception: {}",
                    e.getMessage(),
                    e);

            String message = ZuulFilterResponseUtils.viewTipsMessage(
                    appConfig.isEnableLocalLogPrefix(),
                    appConfig.getLocalAppName(),
                    ZuulResponseConstant.ILLEGAL_TOKEN
            );

            ZuulFilterResponseUtils.sendResponse(ctx,
                    600,
                    message,
                    e.getMessage());

            return null;
        }

        if (inBlackList) {

            LOGGER.info("{} in a black list ! ", accessToken);

            String message = ZuulFilterResponseUtils.viewTipsMessage(
                    appConfig.isEnableLocalLogPrefix(),
                    appConfig.getLocalAppName(),
                    ZuulResponseConstant.IN_BLACK_LIST
            );

            ZuulFilterResponseUtils.sendResponse(ctx,
                    600,
                    message,
                    message);
        }

        return null;
    }

    private boolean accessTokenInBlacklist(String accessToken) {
        //按理说应该将载荷传递下去
        Map<String, String> map = TokenUtils.extractPlayLoad(accessToken);
        String key = TokenUtils.extractBlackListTokenKey(map);
        if (StringUtils.isEmpty(redisStringUtils.get(key))) {
            return false;
        }
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //是否创建黑名单
    }
}
